#include <iostream>
#include <vector>
#include <map>

int g_size = 3;

enum Player {
  DEFAULT = 0,
  PLAYER_A,
  PLAYER_B,
};

const std::map<Player, std::string> player_map = {
    {Player::PLAYER_A, "player_a"},
    {Player::PLAYER_B, "player_b"},
};

template<typename T>
void PrintItem(T t, const std::string& title = "") {
  std::cout << title << t << std::endl;
}

template<typename T>
void PrintContainer(T t) {
  std::string print_line;
  for (const auto &element : t) {
    print_line += (element + ",");
  }
  print_line = print_line.substr(0, print_line.size() - 1);
  std::cout << print_line << std::endl;
}

class Tictactoe {
 public:
  void start_game() {
    init();
    std::cout << "Game start!" << std::endl;

    show_checkerboard();
    Player winner;
    for (; index_ < g_size * g_size; ++index_) {
      int input_number;
      while (true) {
        std::cout << "Please input the position index you want to put:";
        std::cin >> input_number;
        if (input_number >= 1 && input_number <= 9) {
          break;
        } else {
          std::cout << "Input number should in the range of 0~9, please retype." << std::endl;
        }
      }
      refresh_checkerboard(input_number);
      show_checkerboard();
      if (index_ >= 2 * g_size - 2) {
        if (game_over(winner)) {
          break;
        }
      }
    }
    if (winner != Player::DEFAULT) {
      std::cout << "Game over, the winner is " << player_map.at(winner) << "!" << std::endl;
    } else {
      std::cout << "Game over, there's no winner " << std::endl;
    }
  }

 private:
  void init() {
    index_ = 0;
    checkerboard_ = {
        {"[1]", "[2]", "[3]"},
        {"[4]", "[5]", "[6]"},
        {"[7]", "[8]", "[9]"}
    };
  }

  bool game_over(Player &winner) {
    winner = Player::DEFAULT;
    if (is_slant_same_line()) {
      winner = (index_ & 1) == 0 ? Player::PLAYER_A : Player::PLAYER_B;
      return true;
    }
    std::map<std::vector<int>, std::vector<int>> find_map = {
        {{0, 0}, {1, 2}},
        {{1, 1}, {-1, 1}},
        {{2, 2}, {-1, -2}},
    };
    for (const auto &item: find_map) {
      int row = item.first[0];
      int col = item.first[1];
      std::string base = checkerboard_[row][col];
      if (base != "[X]" && base != "[O]") {
        continue;
      }
      if (is_upright_same_line(row, col, item.second, base)) {
        winner = (index_ & 1) == 0 ? Player::PLAYER_A : Player::PLAYER_B;
        return true;
      }
    }
    return false;
  }

  bool is_upright_same_line(const int row, const int col, const std::vector<int>& find_vec, const std::string& base) {
    return ((checkerboard_[row][col + find_vec[0]] == base) && (checkerboard_[row][col + find_vec[1]] == base))
        || ((checkerboard_[row + find_vec[0]][col] == base) && (checkerboard_[row + find_vec[1]][col] == base));
  }

  bool is_slant_same_line() {
    if ((g_size & 1) == 0) {
      return false;
    }
    if (g_size != 3) {
      std::cout << "Please change the func: is_slant_same_line()!!!" << std::endl;
    }
    return (checkerboard_[1][1] == checkerboard_[0][0]) && (checkerboard_[1][1] == checkerboard_[2][2]);
  }

  void show_checkerboard() {
    for (const auto &item: checkerboard_) {
      PrintContainer(item);
    }
  }

  void refresh_checkerboard(const int input) {
    int row = (input - 1) / 3;
    int col = (input - 1) % 3;
    std::string res = (index_ & 1) == 0 ? "[X]" : "[O]";
    checkerboard_[row][col] = res;
  }

 private:
  size_t index_ = 0;
  std::vector<std::vector<std::string>> checkerboard_;
};

int main() {
  std::cout << "Hello, World!" << std::endl;
  Tictactoe game;
  game.start_game();
  return 0;
}
